/*
 * BBMBridge.java
 *
 * This is a partial class from the BBM SDK demo app with modifications and a lot of deletions
 *
 * Research In Motion Limited proprietary and confidential
 * Copyright Research In Motion Limited, 2011-2011
 */
package com.allkapps.bbmopenchat;

import java.util.Vector;

import net.rim.blackberry.api.bbm.platform.BBMPlatformApplication;
import net.rim.blackberry.api.bbm.platform.BBMPlatformContext;
import net.rim.blackberry.api.bbm.platform.BBMPlatformManager;
import net.rim.blackberry.api.bbm.platform.io.BBMPlatformConnection;
import net.rim.blackberry.api.bbm.platform.io.BBMPlatformData;
import net.rim.blackberry.api.bbm.platform.io.BBMPlatformOutgoingJoinRequest;
import net.rim.blackberry.api.bbm.platform.io.BBMPlatformSession;
import net.rim.blackberry.api.bbm.platform.io.ContactUnreachableException;
import net.rim.blackberry.api.bbm.platform.io.DataOverflowException;
import net.rim.blackberry.api.bbm.platform.profile.BBMPlatformContact;
import net.rim.blackberry.api.bbm.platform.profile.BBMPlatformContactList;
import net.rim.blackberry.api.bbm.platform.profile.UserProfile;
import net.rim.blackberry.api.bbm.platform.profile.UserProfileBox;
import net.rim.blackberry.api.bbm.platform.profile.UserProfileBoxAccessException;
import net.rim.blackberry.api.bbm.platform.service.MessagingService;
import net.rim.blackberry.api.bbm.platform.ui.MenuItemManager;
import net.rim.blackberry.api.bbm.platform.ui.chat.MessageSender;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;

import com.allkapps.bbmopenchat.utils.BBMUtils;

/**
 * Manages the platform context registration as well as providing convenience methods for channels, sessions, and other aspects of
 * BBM Platform.
 * <p>
 * The components in this application that use the BBM platform should access the platform context from here.
 * 
 */
public class BBMBridge extends BBMPlatformApplication {

    private BBMPlatformContext _platformContext = null;

    // The list of open connections.
    private Vector _connections = new Vector();

    private BBMOpenChatMessagingServiceListener _messagingServiceListener;

    private static BBMBridge _instance = null;

    static final int MENU_ITEM_ID_NONE = -1;
    static final int MENU_ITEM_ID_DEFAULT = 0;

    /**
     * Retrieve an instance of the bridge.
     * 
     * @return a non null instance of the bridge.
     */
    public static BBMBridge getInstance() {
        if( _instance == null ) {
            _instance = new BBMBridge();
        }

        return _instance;
    }

    private BBMBridge() {
        /* --------------------------------------------------------------------
         * *LOOK_HERE*
         * --------------------------------------------------------------------
         * UUID is used to uniquely identify the application in the test environment
         * before the application is available in AppWorld. If the application exists in
         * AppWorld, the UUID will not be used to identify the application.
         *
         * To run this app, you should generate a different UUID, because there is a
         * limit to the number of users who can share the same UUID.
         *
         * Initialize using a version 1 UUID according to RFC 4122
         * Search for "UUID Generator" on the web to generate a UUID.
         */
        super("0e7d2690-bafd-11e0-962b-0800200c9a66");
    }

    public void registerBBMPlatform() {
        // --------------------------------------------------------------------
        // *LOOK_HERE*
        // Register the plug-in with the BBM Platform
        // --------------------------------------------------------------------
    	try{
    		_platformContext = BBMPlatformManager.register( this );
    	} catch(Exception e){
    		System.out.println(e.getMessage());
    	}
    }

    /**
     * Returns the platform context used by this application.
     * 
     * @return the platform context used by this application; never null.
     */
    public BBMPlatformContext getBBMPlatformContext() {
        if( _platformContext == null ) {
            registerBBMPlatform();
        }

        return _platformContext;
    }
    
    /**
     * Create a BBM Platform Channel for the given channel screen. The controlling listener updates/notifies the screen based on
     * channel events.
     * 
     * @see {@link BBMOpenChatChannelListener}
     */
    public BBMPlatformConnection createChannel() {
        /* --------------------------------------------------------------------
         * *LOOK_HERE*
         * Create a channel.
         * Notice that a listener is required to create a channel.
         * See {@link DemoChannelListener} implementation for details.
         * --------------------------------------------------------------------
         */
        BBMPlatformContext platformContext = getBBMPlatformContext();
        return platformContext.getMessagingService().createChannel( new BBMOpenChatChannelListener(null) );
    }

    /**
     * Creates a new channel and displays the channel screen.
     * 
     * @see {@link BBMOpenChatChannelListener}
     */
    public void newChannel() {
        newConnection( true );
    }

    /**
     * Creates a new session and shows the session screen.
     */
    public void newSession() {
        newConnection( false );
    }

    /**
     * Creates a new connection based on the type and displays the corresponding screen.
     * 
     * @param isChannel
     *            true to create a channel; false to create a session.
     */
    private void newConnection( boolean isChannel ) {
        BBMPlatformConnection connection = isChannel ? createChannel(  ) : createSession(  );
        addConnection( connection );
    }

    /**
     * Adds a connection to be managed and display the connection screen. This is typically called from the message service
     * listener when a channel or session is created.
     * 
     * @param connection
     *            the connection to add.
     * @param connectionScreen
     *            the connection screen.
     */
    public void addConnection( BBMPlatformConnection connection) {
        ConnectionInfo connectionInfo = getConnectionInfo( connection );

        if( connectionInfo == null ) {
            connectionInfo = new ConnectionInfo( connection );
            _connections.addElement( connectionInfo );
        }

    }

    /**
     * Create a BBM Platform session for the given session screen. The controlling listener updates/notifies the screen based on
     * session events.
     * 
     * @see {@link BBMOpenChatSessionListener}
     */
    public BBMPlatformConnection createSession( ) {
        /* --------------------------------------------------------------------
         * *LOOK_HERE*
         * Create a session.
         * Notice that a listener is required to create a session.
         * See {@link DemoSessionListener} implementation for details.
         * --------------------------------------------------------------------
         */
        BBMPlatformContext platformContext = getBBMPlatformContext();
        BBMPlatformConnection conn = platformContext.getMessagingService().createSession( new BBMOpenChatSessionListener() );
        conn.setPublic();
        return conn;
    }

    /**
     * Ends/destroys all connections.
     * 
     */
    public void cleanupConnections() {
        final int numConnections = _connections.size();
        for( int i = 0; i < numConnections; i++ ) {
            ConnectionInfo connectionInfo = (ConnectionInfo) _connections.elementAt( i );
            connectionInfo.cleanup(true);
        }
        _connections.removeAllElements();
    }

    /**
     * Cleans up all resources associated with a connection.
     * 
     * @param connectionInfo
     */
    public void cleanupConnection( BBMPlatformConnection connection, boolean destroy ) {
        if( connection == null ) {
            return;
        }

        cleanupConnection( getConnectionInfo( connection ), destroy );
    }

    /**
     * Cleans up all resources associated with a connection.
     * 
     * @param connectionInfo
     */
    public void cleanupConnection( ConnectionInfo connectionInfo, boolean destroy ) {
        connectionInfo.cleanup(destroy);
        _connections.removeElement( connectionInfo );
    }

    /**
     * Leaves a session and removes it from the connection list. Note that this is different from ending a session.
     * 
     * @param session
     *            the sesion to leave.
     */
    public void leaveSession( BBMPlatformSession session ) {
        ConnectionInfo connectionInfo = getConnectionInfo( session );

        if( connectionInfo != null ) {
            session.leave();
            _connections.removeElement( connectionInfo );
        }
    }

    public ConnectionInfo getConnectionInfo( BBMPlatformConnection connection ) {
        if( connection == null ) {
            return null;
        }

        int numConnections = _connections.size();

        for( int i = 0; i < numConnections; i++ ) {
            ConnectionInfo curConnectionInfo = (ConnectionInfo) _connections.elementAt( i );

            if( curConnectionInfo.getConnection().getId() == connection.getId() ) {
                return curConnectionInfo;
            }
        }
        return null;
    }

    /**
     * Returns the current user's info as a {@link MessageSender} object.
     * 
     * @see {@link net.rim.blackberry.api.bbm.platform.ui.chat.MessageSender}
     */
    public MessageSender getCurrentUserMessageSender() {
        /* --------------------------------------------------------------------
         * *LOOK_HERE*
         * Message senders are used to identify the sender of a message in a chat.
         * --------------------------------------------------------------------
         */
        return new MessageSender( _platformContext.getUserProfile().getDisplayName() );
    }

    /**
     * Sends a message as text to all of the contacts of a given connection. This method uses the generic
     * {@link BBMPlatformConnection#sendData(BBMPlatformData, BBMPlatformContactList) sendData} method to send data. It does not
     * use the channel or session specific methods.
     * 
     * @param message
     *            message to send
     * @param connection
     *            connection to use.
     * 
     * @throws DataOverflowException
     *             if data sent by the application has exceeded the data rate capped by the BBM Platform
     * @throws ContactUnreachableException
     *             if pending data for an unreachable contact in the destination has exceeded the buffer limit set by the BBM
     *             Platform
     * @throws NullPointerException
     *             if <code>message</code> or <code>connection</code> is null.
     * 
     * @see {@link BBMPlatformConnection#sendData(BBMPlatformData, BBMPlatformContactList) sendData}
     */
    public void sendTextMessage( String message, BBMPlatformConnection connection ) throws DataOverflowException,
            ContactUnreachableException {
        /* --------------------------------------------------------------------
         * *LOOK_HERE*
         * sendData can be used to send any type of data over the connection.
         * For demo purposes, we're just sending text messages.
         * --------------------------------------------------------------------
         */
        BBMPlatformContactList contactList = connection.getContactList();
        if( connection.getContactList().size() > 0 ) {
            BBMPlatformData data = new BBMPlatformData( message );
            connection.sendData( data, contactList );
        }
    }

    /**
     * Removes a contact from a connection, but ignores any errors about the contact not being a member.
     * 
     * @param contact
     *            the contact to remove
     * @param connection
     *            the connection from which to remove the contact.
     * 
     * @throws NullPointerException
     *             if <code>contact</code> or <code>connection</code> is null.
     * 
     * @see {@link BBMPlatformConnection#remove(BBMPlatformContact)}
     */
    public void removeContact( BBMPlatformContact contact, BBMPlatformConnection connection ) {
        try {
            /* --------------------------------------------------------------------
             * *LOOK_HERE*
             * remove a contact for the connection.
             * --------------------------------------------------------------------
             */
            connection.remove( contact );
        } catch( IllegalArgumentException e ) {
            // ignore membership errors
        } catch( IllegalStateException e ) {
        }

    }

    /**
     * Adds a profile box item to the current user's profile.
     * 
     * Note that this may be a long running operations since some image resizing may occur. It's best to run this in a background
     * thread and not on a UI thread.
     * 
     * @param iconId
     *            the icon id to use/register. This is ignored if icon is null.
     * @param icon
     *            The icon to use; may be null.
     * @param text
     *            The text for the profile box item.
     */
    public void addProfileBoxItem( int iconId, EncodedImage icon, String text ) {
        BBMPlatformContext bbmPlatformContext = getBBMPlatformContext();
        UserProfile userProfile = bbmPlatformContext.getUserProfile();
        String exceptionText = null;
        try {
            UserProfileBox profileBox = userProfile.getProfileBox();
            if( profileBox != null && profileBox.isAccessible() ) {
                if( icon != null ) {
                    // icon is non null. Add an icon
                    // along with the entered text
                    profileBox.addItem( iconId, text );
                } else {
                    // icon is null. Just add the text to profile
                    // box
                    profileBox.addItem( text );
                }
            }
        } catch( UserProfileBoxAccessException e ) {
            exceptionText = e.getMessage();
        } catch( IllegalArgumentException e ) {
            exceptionText = e.getMessage();
        } finally {
            if( exceptionText != null ) {
                final String message = exceptionText;
                UiApplication.getUiApplication().invokeLater( new Runnable() {
                    public void run() {
                        Dialog.inform( message );
                    }
                } );
            }
        }

    }

    public void registerProfileBoxIcon( final int iconId, final EncodedImage icon ) {
        UiApplication.getUiApplication().invokeLater( new Runnable() {
            public void run() {
                BBMPlatformContext bbmPlatformContext = getBBMPlatformContext();
                UserProfile userProfile = bbmPlatformContext.getUserProfile();
                String exceptionText = null;
                try {
                    UserProfileBox profileBox = userProfile.getProfileBox();
                    if( profileBox != null && profileBox.isAccessible() ) {
                        if( icon != null ) {
                            profileBox.registerIcon( iconId, icon );
                        }
                    }
                } catch( UserProfileBoxAccessException e ) {
                    exceptionText = e.getMessage();
                } catch( IllegalArgumentException e ) {
                    exceptionText = e.getMessage();
                } finally {
                    if( exceptionText != null ) {
                        final String message = exceptionText;
                        UiApplication.getUiApplication().invokeLater( new Runnable() {
                            public void run() {
                                Dialog.inform( message );
                            }
                        } );
                    }
                }
            }
        } );

    }

    public String getChannelDescription( int menuItemId ) {
        return "";
    }

    /**
     * Adds a channel invitation menu item to the BBM contact list. This should be called when we're successfully registered.
     */
    public boolean addChannelInvitationMenuItem() {
        BBMPlatformContext platformContext = getBBMPlatformContext();

        if( platformContext == null ) {
            return false;
        }

        MenuItemManager menuItemManager = platformContext.getUIService().getMenuItemManager();

        int menuItemId = MENU_ITEM_ID_DEFAULT; // we are not adding multiple menu items, so we'll reuse this ID everytime.
        try {
           menuItemManager.addChannelInvitationMenuItem( menuItemId,
                   "Invite", getChannelDescription( menuItemId ),
                   menuItemId );
        } catch( IllegalArgumentException e ) {
             // Silently catch the exception as this menu item is added on the startup   
        } 

        return true;
    }

    /**
     * Sends a join request and parses the PIN string.
     * 
     * @param hostPinString
     *            the PIN to parse.
     * @param ppid
     *            the PPID
     * @return the join request if it was made successfully.
     * 
     * @throws NullPointerException
     *             if the pin or ppid is null.
     * @throws NumberFormatException
     *             if the pin string is not a hex number.
     * 
     */
    public BBMPlatformOutgoingJoinRequest sendJoinRequest( String hostPinString, String ppid ) {
        int pin = BBMUtils.parsePin( hostPinString );
        return sendJoinRequest( pin, ppid);
    }

    /**
     * Sends a join request to the PIN and PPID.
     * 
     * @param hostPin
     *            the pin of the host.
     * @param ppid
     *            the PPID of the host.
     * @return a join request if it was made successfully.
     * 
     * @throws IllegalArgumentException
     *             if the pin or PPID is invalid.
     */
    public BBMPlatformOutgoingJoinRequest sendJoinRequest( int hostPin, String ppid) {
        BBMPlatformContext platformContext = getBBMPlatformContext();
        MessagingService messagingService = platformContext.getMessagingService();
        if(hostPin > 0x7FFFFFFF){
        	System.out.println("PIN too big");
        }
        System.out.println("Sending request to " + ppid);
        BBMPlatformOutgoingJoinRequest joinRequest = messagingService.sendJoinRequest( hostPin, ppid, null );

        return joinRequest;
    }

    public void cancelJoinRequest( BBMPlatformOutgoingJoinRequest outgoingJoinrequest ) {
        outgoingJoinrequest.cancel();
    }

    /**
     * Transfer a file to a contact to be selected by the user.
     * 
     * @param filePath
     *            path to the file to be sent
     * @param desc
     *            description of the file
     */
    public void sendFile( String filePath, String desc ) {
        _platformContext.getMessagingService().sendFile( filePath, desc );
        // the callback fileTransferFailed in DemoMessagingServiceListner.java
    }

    /**
     * Transfer a file to a contact.
     * 
     * @param filePath
     *            path to the file to be sent
     * @param desc
     *            description of the file
     */
    public void sendFile( BBMPlatformContact contact, String filePath, String desc ) {
        _platformContext.getMessagingService().sendFile( contact, filePath, desc );
        // the callback fileTransferFailed in DemoMessagingServiceListner.java
    }

    /**
     * This should be called when BBM platform context listener gets an "access allowed" message.
     */
    void accessAllowed() {
        if( _messagingServiceListener == null ) {
            _messagingServiceListener = new BBMOpenChatMessagingServiceListener(null);
        }

        getBBMPlatformContext().getMessagingService().setServiceListener( _messagingServiceListener );
        addChannelInvitationMenuItem();
    }

}
